package pers.mihao.quickstream.common.util;

import pers.mihao.quickstream.common.exception.BaseException;
import pers.mihao.quickstream.common.model.GetSetDTO;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author mihao
 * @since 2023/3/21
 */
public class GetSetUtil {

    private static final String GET = "get";

    private static final String SET = "set";

    private static Map<Class<?>, Map<String, GetSetDTO>> GET_SET_MAP = new HashMap<>(16);


    public static Object setValueBySetter(String fieldName, Object obj, String value) {
        Method setter = getSetter(fieldName, obj.getClass());
        try {
            return setter.invoke(value);
        } catch (Exception e) {
            throw new BaseException(e);
        }
    }

    public static Object getValueByGetter(String fieldName, Object obj) throws ReflectiveOperationException {
        Method getter = getGetter(fieldName, obj.getClass());
        if (getter != null) {
            return getter.invoke(obj);
        }

        return null;
    }

    /**
     * 获取一个类的所有getset
     *
     * @param clazz
     * @return
     */
    public static Map<String, GetSetDTO> getAllGetSetMethod(Class<?> clazz) {
        Map<String, GetSetDTO> all;
        if ((all = GET_SET_MAP.get(clazz)) == null) {
            all = new HashMap<>(16);
            List<Field> fs = ReflectionUtil.listFields(clazz);
            Method[] methods = clazz.getMethods();
            String getName, setName;
            for (Field field : fs) {
                Method get = null, set = null;
                getName = GET.concat(getMethodField(field.getName()));
                setName = SET.concat(getMethodField(field.getName()));
                for (Method method : methods) {
                    if (get != null && set != null) {
                        break;
                    } else {
                        if (get == null && method.getName().equals(getName)) {
                            get = method;
                            continue;
                        }
                        if (set == null && method.getName().equals(setName)) {
                            set = method;
                        }
                    }
                }
                if (set != null && get != null) {
                    all.put(field.getName(), new GetSetDTO(get, set));
                }
            }
            GET_SET_MAP.put(clazz, all);
        }
        return all;
    }


    /**
     * 获取set方法
     *
     * @param fieldName
     * @param cls
     * @return
     */
    public static Method getSetter(String fieldName, Class<?> cls) {
        for (Method method : cls.getMethods()) {
            if (method.getName().equalsIgnoreCase("set".concat(fieldName)) && method.getParameterTypes().length == 0) {
                return method;
            }
        }
        return null;
    }

    /**
     * 获取字段对应的get方法
     *
     * @param fieldName
     * @param clazz
     * @return
     */
    public static Method getGetter(String fieldName, Class<?> clazz) {
        String methodName = GET.concat(getMethodField(fieldName));
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if (method.getName().equals(methodName) && method.getParameterTypes().length == 0) {
                return method;
            }
        }
        return null;
    }


    private static String getMethodField(String name) {
        if (name != null && name.length() > 0) {
            return Character.toUpperCase(name.charAt(0)) + name.substring(1);
        }
        throw new BaseException();
    }
}
